/******************************************************************************

    Hitachi HD61700 cpu core emulation.
    by Sandro Ronco

    This CPU core is based on documentations works done by:
    - Piotr Piatek ( http://www.pisi.com.pl/piotr433/pb1000he.htm )
    - BLUE ( http://www.geocities.jp/hd61700lab/ )

    The HD61700 has 0x1800 bytes of internal ROM accessed as 16bit with address
    shift by -1 (mapped from 0x0000 to 0x0c00), the external memory is accessed
    with a 8bit data bus, this core emulate all memory as 16bit access with
    address shifted by -1 and in the memory above 0x0c00 only the lower 8bit
    are used.

    TODO:
    - dasm don't decode some mnemonics
    - CPU fast/slow mode
    - probably other minor things

******************************************************************************/

#include "emu.h"
#include "debugger.h"
#include "hd61700.h"

// internal ROM
#define INT_ROM					0x0c00

// 5 bit registers
#define REG_SX					m_regsir[0]
#define REG_SY					m_regsir[1]
#define REG_SZ					m_regsir[2]
#define READ_SREG(a)			(m_regsir[((a)>>5) & 0x03] & 0x1f)
#define WRITE_SREG(a,d)			(m_regsir[((a)>>5) & 0x03] = (d) & 0x1f)

// 8 bit registers
#define REG_PE					m_reg8bit[0]
#define REG_PD					m_reg8bit[1]
#define REG_IB					m_reg8bit[2]
#define REG_UA					m_reg8bit[3]
#define REG_IA					m_reg8bit[4]
#define REG_IE					m_reg8bit[5]
#define REG_TM					m_reg8bit[7]
#define READ_REG8(a)			(m_reg8bit[(a) & 0x07])
#define WRITE_REG8(a,d)			(m_reg8bit[(a) & 0x07] = d)

// 16 bit registers
#define REG_IX					m_reg16bit[0]
#define REG_IY					m_reg16bit[1]
#define REG_IZ					m_reg16bit[2]
#define REG_US					m_reg16bit[3]
#define REG_SS					m_reg16bit[4]
#define REG_KY					m_reg16bit[5]

// main registers
#define READ_REG(a)				(m_regmain[(a) & 0x1f])
#define WRITE_REG(a,d)			(m_regmain[(a) & 0x1f] = d)
#define COPY_REG(d,s)			(m_regmain[(d) & 0x1f] = m_regmain[(s) & 0x1f])
#define REG_GET16(r)			(((m_regmain[((r)) & 0x1f]<<0)) | (m_regmain[((r) + 1) & 0x1f]<<8))
#define REG_PUT16(r,d)			do{(m_regmain[(r) & 0x1f] = (((d)>>0) & 0xff)); (m_regmain[((r)+1)&0x1f]=(((d)>>8)&0xff));}while(0)

// opcode
#define GET_REG_IDX(a,b)		(((a<<2) & 0x04) | ((b>>5) & 0x03))
#define	RESTORE_REG(o,r,pr)		r = (o&0x02) ? r : pr
#define COND_WRITE_REG(o,a,d)	if (o&0x08) WRITE_REG(a,d)
#define GET_IM3(d)				(((d>>5)&0x07) + 1)

// flags
#define	SET_FLAG_C				m_flags |= FLAG_C
#define	CLEAR_FLAG_Z			m_flags |= FLAG_Z
#define	CLEAR_FLAG_LZ			m_flags |= FLAG_LZ
#define	CLEAR_FLAG_UZ			m_flags |= FLAG_UZ
#define	CLEAR_FLAGS				m_flags &= ~(FLAG_Z | FLAG_C | FLAG_LZ | FLAG_UZ)

#define CHECK_FLAG_Z(d)			if((d) != 0) CLEAR_FLAG_Z
#define CHECK_FLAG_C(d,l)		if (d > l) SET_FLAG_C
#define CHECK_FLAGB_LZ(d)		if(((d) & 0x0f) != 0) CLEAR_FLAG_LZ
#define CHECK_FLAGB_UZ(d)		if(((d) & 0xf0) != 0) CLEAR_FLAG_UZ
#define CHECK_FLAGW_LZ(d)		if(((d) & 0x0f00) != 0) CLEAR_FLAG_LZ
#define CHECK_FLAGW_UZ(d)		if(((d) & 0xf000) != 0) CLEAR_FLAG_UZ
#define CHECK_FLAGB_UZ_LZ(d)	do{CHECK_FLAGB_LZ(d); CHECK_FLAGB_UZ(d);}while(0)
#define CHECK_FLAGW_UZ_LZ(d)	do{CHECK_FLAGW_LZ(d); CHECK_FLAGW_UZ(d);}while(0)

//CPU state
#define	CPU_FAST				0x01
#define	CPU_SLP 				0x02

/* HD61700 IRQ vector */
static const UINT16 irq_vector[] = {0x0032, 0x0042, 0x0052, 0x0062, 0x0072};

//**************************************************************************
//  HD61700 DEVICE
//**************************************************************************

const device_type HD61700 = &device_creator<hd61700_cpu_device>;

//-------------------------------------------------
//  hd61700_cpu_device - constructor
//-------------------------------------------------

hd61700_cpu_device::hd61700_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
	: cpu_device(mconfig, HD61700, "HD61700", tag, owner, clock),
	 m_program_config("program", ENDIANNESS_BIG, 16, 18, -1)
{
	memset(&m_partial_frame_period, 0, sizeof(m_partial_frame_period));
}


//-------------------------------------------------
//  static_set_config - set the configuration
//  structure
//-------------------------------------------------

void hd61700_cpu_device::static_set_config(device_t &device, const hd61700_config &config)
{
	hd61700_cpu_device &conf = downcast<hd61700_cpu_device &>(device);
	static_cast<hd61700_config &>(conf) = config;
}

//-------------------------------------------------
//  device_start - start up the device
//-------------------------------------------------

void hd61700_cpu_device::device_start()
{
	m_program = this->space(AS_PROGRAM);

	m_sec_timer = timer_alloc(SEC_TIMER);
	m_sec_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));

	// save state
	save_item(NAME(m_ppc));
	save_item(NAME(m_curpc));
	save_item(NAME(m_pc));
	save_item(NAME(m_flags));
	save_item(NAME(m_fetch_addr));
	save_item(NAME(m_irq_status));
	save_item(NAME(m_state));
	save_item(NAME(prev_ua));
	save_item(NAME(m_icount));
	save_item(NAME(m_regsir));
	save_item(NAME(m_reg8bit));
	save_item(NAME(m_reg16bit));
	save_item(NAME(m_regmain));
	save_item(NAME(m_lines_status));

	// register state for debugger
	state_add(HD61700_PC, "pc",   m_pc).callimport().callexport().formatstr("%04X");
	state_add(HD61700_F,  "f", m_flags).callimport().callexport().formatstr("%02X");
	state_add(HD61700_SX, "SX", REG_SX).callimport().callexport().formatstr("%02X");
	state_add(HD61700_SY, "SY", REG_SY).callimport().callexport().formatstr("%02X");
	state_add(HD61700_SZ, "SZ", REG_SZ).callimport().callexport().formatstr("%02X");

	state_add(HD61700_PE, "pe", REG_PE).callimport().callexport().formatstr("%02X");
	state_add(HD61700_PD, "pd", REG_PD).callimport().callexport().formatstr("%02X");
	state_add(HD61700_IB, "ib", REG_IB).callimport().callexport().formatstr("%02X");
	state_add(HD61700_UA, "ua", REG_UA).callimport().callexport().formatstr("%02X");
	state_add(HD61700_IA, "ia", REG_IA).callimport().callexport().formatstr("%02X");
	state_add(HD61700_IE, "ie", REG_IE).callimport().callexport().formatstr("%02X");
	state_add(HD61700_TM, "tm", REG_TM).callimport().callexport().formatstr("%02X");

	state_add(HD61700_IX, "ix", REG_IX).callimport().callexport().formatstr("%04X");
	state_add(HD61700_IY, "iy", REG_IY).callimport().callexport().formatstr("%04X");
	state_add(HD61700_IZ, "iz", REG_IZ).callimport().callexport().formatstr("%04X");
	state_add(HD61700_US, "us", REG_US).callimport().callexport().formatstr("%04X");
	state_add(HD61700_SS, "ss", REG_SS).callimport().callexport().formatstr("%04X");
	state_add(HD61700_KY, "ky", REG_KY).callimport().callexport().formatstr("%04X");

	for (int ireg=0; ireg<32; ireg++)
	{
		astring tmpstr;
		state_add(HD61700_MAINREG + ireg, tmpstr.format("R%d", ireg), m_regmain[ireg]).callimport().callexport().formatstr("%02X");
	}

	state_add(STATE_GENPC, "curpc", m_curpc).callimport().callexport().formatstr("%8s").noshow();
	state_add(STATE_GENPCBASE, "curpcbase", m_ppc).callimport().callexport().formatstr("%8s").noshow();
	state_add(STATE_GENFLAGS, "GENFLAGS",  m_flags).mask(0xff).formatstr("%8s").noshow();

	// set our instruction counter
	m_icountptr = &m_icount;
}


//-------------------------------------------------
//  device_reset - reset up the device
//-------------------------------------------------

void hd61700_cpu_device::device_reset()
{
	m_ppc = 0x0000;
	m_curpc = 0x0000;
	set_pc(0x0000);
	m_flags = FLAG_SW;
	m_icount = 0;
	m_state = 0;
	m_irq_status = 0;
	prev_ua = 0;

	memset(m_regsir, 0, ARRAY_LENGTH(m_regsir));
	memset(m_reg8bit, 0, ARRAY_LENGTH(m_reg8bit));
	memset(m_reg16bit, 0, ARRAY_LENGTH(m_reg16bit) * sizeof(UINT16));
	memset(m_regmain, 0, ARRAY_LENGTH(m_regmain));

	for (int i=0;i<6; i++)
		m_lines_status[i] = CLEAR_LINE;
}



//-------------------------------------------------
//  device_timer - handler timer events
//-------------------------------------------------
void hd61700_cpu_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
	switch(id)
	{
		case SEC_TIMER:
			REG_TM++;
			if ((REG_TM&0x3f) == 60)
			{
				REG_TM = (REG_TM & 0xc0) + 0x40;

				if (((REG_IE>>3) & (1<<HD61700_TIMER_INT)))
				{
					REG_IB |= (1<<HD61700_TIMER_INT);

					if (REG_IB & 0x20)
					{
						m_state &= ~CPU_SLP;
						m_flags |= FLAG_APO;
					}
				}
			}
			break;
	}
}



//-------------------------------------------------
//  state_import - import state into the device,
//  after it has been set
//-------------------------------------------------

void hd61700_cpu_device::state_import(const device_state_entry &entry)
{
	switch (entry.index())
	{
		case HD61700_PC:
			set_pc(m_pc);
			break;
	}
}

//-------------------------------------------------
//  state_string_export - export state as a string
//  for the debugger
//-------------------------------------------------

void hd61700_cpu_device::state_string_export(const device_state_entry &entry, astring &string)
{
	switch (entry.index())
	{
		case STATE_GENFLAGS:
			string.printf("%c%c%c%c%c%c",
				m_flags & FLAG_Z   ? '.' : 'Z',
				m_flags & FLAG_C   ? 'C' : '.',
				m_flags & FLAG_LZ  ? '.' : 'L',
				m_flags & FLAG_UZ  ? '.' : 'U',
				m_flags & FLAG_SW  ? 'S' : '.',
				m_flags & FLAG_APO ? 'A' : '.'
			);
			break;
	}
}



//-------------------------------------------------
//  disasm_disassemble - call the disassembly
//  helper function
//-------------------------------------------------

offs_t hd61700_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
{
	extern CPU_DISASSEMBLE( hd61700 );
	return CPU_DISASSEMBLE_NAME(hd61700)(NULL, buffer, pc, oprom, opram, 0);
}



//-------------------------------------------------
//  check_irqs - check if need interrupts
//-------------------------------------------------

bool hd61700_cpu_device::check_irqs(void)
{
	for (int i=4; i>=0; i--)
	{
		if (REG_IB & (1<<i) && !(m_irq_status & (1<<i)))
		{
			m_irq_status |= (1<<i);
			push(REG_SS, (m_pc>>8)&0xff);
			push(REG_SS, (m_pc>>0)&0xff);

			set_pc(irq_vector[i]);
			m_icount -= 12;
			return true;
		}
	}

	return false;
}


//-------------------------------------------------
//  execute - execute for the provided number of
//  cycles
//-------------------------------------------------

void hd61700_cpu_device::execute_run()
{
	do
	{
		debugger_instruction_hook(this, m_curpc);

		// verify that CPU is not in sleep
		if (m_state & CPU_SLP)
		{
			m_icount -= 6;
		}
		else
		{
			UINT8 op;

			check_irqs();

			m_ppc = m_curpc;

			// instruction fetch
			op = read_op();

			// execute the instruction
			switch ( op )
			{
				case 0x00:	//adc
				case 0x01:	//sbc
				case 0x08:	//ad
				case 0x09:	//sb
					{
						UINT8 arg = read_op();
						UINT8 src = READ_REG(get_sir_im8(arg));
						UINT16 res = READ_REG(arg) + ((op&1) ? -src : +src);

						COND_WRITE_REG(op, arg, res & 0xff);

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res & 0xff);
						CHECK_FLAGB_UZ_LZ(res);
						CHECK_FLAG_C(res, 0xff);

						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x02:	//ld
					{
						UINT8 arg = read_op();
						COPY_REG(arg, get_sir_im8(arg));

						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x04:	//anc
				case 0x05:	//nac
				case 0x06:	//orc
				case 0x07:	//xrc
				case 0x0c:	//an
				case 0x0d:	//na
				case 0x0e:	//or
				case 0x0f:	//xr
					{
						UINT8 arg = read_op();

						UINT8 res = make_logic(op, READ_REG(arg),  READ_REG(get_sir_im8(arg)));

						COND_WRITE_REG(op, arg, res);

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res & 0xff);
						CHECK_FLAGB_UZ_LZ(res);

						//na(c) and or(c) always set C flag
						if ((op&3) == 1 || (op&3) == 2)
							SET_FLAG_C;

						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x0a:	//adb
				case 0x0b:	//sbb
					{
						UINT8 arg = read_op();
						UINT16 res;

						if (op & 0x01)
							res = make_bcd_sub(READ_REG(arg), READ_REG(get_sir_im8(arg)));
						else
							res = make_bcd_add(READ_REG(arg), READ_REG(get_sir_im8(arg)));

						WRITE_REG(arg, res & 0xff);

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res & 0xff);
						CHECK_FLAGB_UZ_LZ(res);
						CHECK_FLAG_C(res, 0xff);

						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x10:	//st
					{
						UINT8 arg = read_op();
						UINT8 src = get_sir_im8(arg);
						UINT16 offset = REG_GET16(src);

						mem_writebyte(REG_UA>>4, offset, READ_REG(arg));

						check_optional_jr(arg);
						m_icount -= 8;
					}
					break;

				case 0x11:	//ld
					{
						UINT8 arg = read_op();
						UINT8 src = get_sir_im8(arg);
						UINT16 offset = REG_GET16(src);

						WRITE_REG(arg, mem_readbyte(REG_UA>>4, offset));

						check_optional_jr(arg);
						m_icount -= 8;
					}
					break;

				case 0x12:	//stl
					{
						UINT8 arg = read_op();

						if (m_lcd_data_w)
							(*m_lcd_data_w)(*this, READ_REG(arg));

						check_optional_jr(arg);
						m_icount -= 11;
					}
					break;

				case 0x13:	//ldl
					{
						UINT8 arg = read_op();
						UINT8 res = 0xff;

						if (m_lcd_data_r)
							res = (*m_lcd_data_r)(*this);

						WRITE_REG(arg, res);

						check_optional_jr(arg);
						m_icount -= 11;
					}
					break;

				case 0x14:	//ppo/pfl
					{
						UINT8 arg = read_op();

						if (arg & 0x40)
						{
							m_flags = (m_flags & 0x0f) | (READ_REG(arg) & 0xf0);
						}
						else
						{
							if (m_lcd_control)
								(*m_lcd_control)(*this, READ_REG(arg));
						}

						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x15:	//psr
					{
						UINT8 arg = read_op();
						WRITE_SREG(arg, READ_REG(arg)&0x1f);

						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x16:	//pst
				case 0x17:	//pst
					{
						UINT8 arg = read_op();
						UINT8 src = READ_REG(arg);
						UINT8 idx = GET_REG_IDX(op, arg);

						switch (idx)
						{
							case 0:		//PE
							case 1:		//PD
								WRITE_REG8(idx, src);
								if (m_port_w)
									(*m_port_w)(*this, REG_PD & REG_PE);
								break;
							case 2:		//IB
								REG_IB = (REG_IB & 0x1f) | (src & 0xe0);
								break;
							case 3:		//UA
								WRITE_REG8(idx, src);
								break;
							case 4:		//IA
								if (m_kb_w)
									(*m_kb_w)(*this, src);
								WRITE_REG8(idx, src);
								break;
							case 5:		//IE
								REG_IB &= (((src>>3)&0x1f) | 0xe0);
								m_irq_status &= ((src>>3)&0x1f);
								WRITE_REG8(idx, src);
								break;
							case 6:		//TM
							case 7:		//TM
								// read-only
								break;
						}

						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x18:
					{
						UINT8 arg = read_op();
						UINT8 op1 = (arg>>5) & 0x03;
						switch (op1)
						{
							case 0x00:	//rod
							case 0x02:	//bid
								{
									UINT8 src = READ_REG(arg);
									UINT8 res = (src>>1)&0x7f;

									if (!(op1&0x02))
										res = res | ((m_flags&FLAG_C) !=0 )<<7;

									WRITE_REG(arg, res);

									CLEAR_FLAGS;
									CHECK_FLAG_Z(res & 0xff);
									CHECK_FLAGB_UZ_LZ(res);
									if (src&0x01) SET_FLAG_C;
								}
								break;

							case 0x01:	//rou
							case 0x03:	//biu
								{
									UINT8 src = READ_REG(arg);
									UINT8 res = (src<<1)&0xfe;

									if (!(op1&0x02))
										res = res | ((m_flags&FLAG_C) !=0 )<<0;

									WRITE_REG(arg, res);

									CLEAR_FLAGS;
									CHECK_FLAG_Z(res & 0xff);
									CHECK_FLAGB_UZ_LZ(res);
									if (src&0x80) SET_FLAG_C;
								}
								break;
						}

						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x1a:
					{
						UINT8 arg = read_op();
						UINT8 op1 = (arg>>5) & 0x03;
						switch (op1)
						{
							case 0x00:	//did
							case 0x01:	//diu
								{
									UINT8 res;

									if (op1&0x01)
										res = (READ_REG(arg)<<4)&0xf0;
									else
										res = (READ_REG(arg)>>4)&0x0f;

									WRITE_REG(arg, res);

									CLEAR_FLAGS;
									CHECK_FLAG_Z(res & 0xff);
									CHECK_FLAGB_UZ_LZ(res);
								}
								break;
							case 0x02:	//byd
							case 0x03:	//byu
								{
									WRITE_REG(arg, 0);
									CLEAR_FLAGS;
									break;
								}
						}

						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x1b:	//cmp/inv
					{
						UINT8 arg = read_op();
						UINT8 res = ~(READ_REG(arg));
						if (!(arg & 0x40)) res++;

						WRITE_REG(arg, res);

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res & 0xff);
						CHECK_FLAGB_UZ_LZ(res);
						if (res || (arg & 0x40)) SET_FLAG_C;

						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x1c:	//gpo/gfl
					{
						UINT8 arg = read_op();
						UINT8 src = 0xff;

						if (arg&0x40)
						{
							src = m_flags;
						}
						else
						{
							if (m_port_r)
								src = (*m_port_r)(*this);

							src&=(~REG_PE);
						}

						WRITE_REG(arg, src);

						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x1d:	//gsr
					{
						UINT8 arg = read_op();
						WRITE_REG(arg, READ_SREG(arg));
						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x1e:	//gst
				case 0x1f:	//gst
					{
						UINT8 arg = read_op();
						UINT8 idx = GET_REG_IDX(op, arg);
						WRITE_REG(arg, READ_REG8(idx));
						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x20:	//st
				case 0x22:	//sti
					{
						UINT8 arg = read_op();
						UINT16 prev_ir = REG_IX;
						REG_IX += get_sign_mreg(arg);

						mem_writebyte(REG_UA>>4, REG_IX++, READ_REG(arg));

						RESTORE_REG(op, REG_IX, prev_ir);

						m_icount -= 8;
					}
					break;

				case 0x21:	//st
				case 0x23:	//sti
					{
						UINT8 arg = read_op();
						UINT16 prev_ir = REG_IZ;
						REG_IZ += get_sign_mreg(arg);

						mem_writebyte(REG_UA>>6, REG_IZ++, READ_REG(arg));

						RESTORE_REG(op, REG_IZ, prev_ir);

						m_icount -= 8;
					}
					break;

				case 0x24:	//std
					{
						UINT8 arg = read_op();
						REG_IX += get_sign_mreg(arg);

						mem_writebyte(REG_UA>>4, REG_IX, READ_REG(arg));
						m_icount -= 6;
					}
					break;

				case 0x25:	//std
					{
						UINT8 arg = read_op();
						REG_IZ += get_sign_mreg(arg);

						mem_writebyte(REG_UA>>6, REG_IZ, READ_REG(arg));
						m_icount -= 6;
					}
					break;

				case 0x26:	//phs
					{
						UINT8 arg = read_op();

						push(REG_SS, READ_REG(arg));
						m_icount -= 9;
					}
					break;
				case 0x27:	//phu
					{
						UINT8 arg = read_op();

						push(REG_US, READ_REG(arg));
						m_icount -= 9;
					}
					break;

				case 0x28:	//ld
				case 0x2a:	//ldi
					{
						UINT8 arg = read_op();
						UINT16 prev_ir = REG_IX;
						REG_IX += get_sign_mreg(arg);

						WRITE_REG(arg, mem_readbyte(REG_UA>>4, REG_IX++));

						RESTORE_REG(op, REG_IX, prev_ir);

						m_icount -= 8;
					}
					break;

				case 0x29:	//ld
				case 0x2b:	//ldi
					{
						UINT8 arg = read_op();
						UINT16 prev_ir = REG_IZ;
						REG_IZ += get_sign_mreg(arg);

						WRITE_REG(arg, mem_readbyte(REG_UA>>6, REG_IZ++));

						RESTORE_REG(op, REG_IZ, prev_ir);

						m_icount -= 8;
					}
					break;

				case 0x2c:	//ldd
					{
						UINT8 arg = read_op();
						REG_IX += get_sign_mreg(arg);

						WRITE_REG(arg, mem_readbyte(REG_UA>>4, REG_IX));

						m_icount -= 6;
					}
					break;

				case 0x2d:	//ldd
					{
						UINT8 arg = read_op();
						REG_IZ += get_sign_mreg(arg);

						WRITE_REG(arg, mem_readbyte(REG_UA>>6, REG_IZ));

						m_icount -= 6;
					}
					break;

				case 0x2e:	//pps
					{
						UINT8 arg = read_op();
						WRITE_REG(arg, pop(REG_SS));

						m_icount -= 11;
					}
					break;
				case 0x2f:	//ppu
					{
						UINT8 arg = read_op();
						WRITE_REG(arg, pop(REG_US));

						m_icount -= 11;
					}
					break;

				case 0x30:	//jp z
				case 0x31:	//jp nc
				case 0x32:	//jp lz
				case 0x33:	//jp uz
				case 0x34:	//jp nz
				case 0x35:	//jp c
				case 0x36:	//jp nlz
				case 0x37:	//unconditional jp
					{
						UINT8 lsb = read_op();
						if (m_pc < INT_ROM) read_op();
						UINT8 msb = read_op();

						if (check_cond(op))
							set_pc((msb<<8) | lsb);
						m_icount -= 3;
					}
					break;

				case 0x38:	//adc
				case 0x3a:	//sbc
				case 0x3c:	//ad
				case 0x3e:	//sb
					{
						UINT8 arg = read_op();
						UINT16 offset = REG_IX + get_sign_mreg(arg);
						UINT8 src = mem_readbyte(REG_UA>>4, offset);

						UINT16 res = src + ((op & 2) ? -READ_REG(arg) : +READ_REG(arg)) ;

						if ((op & 4))
							mem_writebyte(REG_UA>>4, offset, res & 0xff);

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res & 0xff);
						CHECK_FLAGB_UZ_LZ(res);
						CHECK_FLAG_C(res, 0xff);

						m_icount -= 9;
					}
					break;

				case 0x39:	//adc
				case 0x3b:	//sbc
				case 0x3d:	//ad
				case 0x3f:	//sb
					{
						UINT8 arg = read_op();
						UINT16 offset = REG_IZ + get_sign_mreg(arg);
						UINT8 src = mem_readbyte(REG_UA>>6, offset);

						UINT16 res = src + ((op & 2) ? -READ_REG(arg) : +READ_REG(arg)) ;

						if ((op & 4))
							mem_writebyte(REG_UA>>6, offset, res & 0xff);

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res & 0xff);
						CHECK_FLAGB_UZ_LZ(res);
						CHECK_FLAG_C(res, 0xff);

						m_icount -= 9;
					}
					break;

				case 0x40:	//adc
				case 0x41:	//sbc
				case 0x48:	//ad
				case 0x49:	//sb
					{
						UINT8 arg = read_op();
						UINT8 src = read_op();
						UINT16 res = READ_REG(arg) + ((op&1) ? -src : +src);

						COND_WRITE_REG(op, arg, res & 0xff);

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res & 0xff);
						CHECK_FLAGB_UZ_LZ(res);
						CHECK_FLAG_C(res, 0xff);

						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x42:	//ld
					{
						UINT8 arg = read_op();
						UINT8 src = read_op() ;

						WRITE_REG(arg, src);

						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x44:	//anc
				case 0x45:	//nac
				case 0x46:	//orc
				case 0x47:	//xrc
				case 0x4c:	//an
				case 0x4d:	//na
				case 0x4e:	//or
				case 0x4f:	//xr
					{
						UINT8 arg = read_op();
						UINT8 src = read_op();

						UINT8 res = make_logic(op, READ_REG(arg), src);

						COND_WRITE_REG(op, arg, res);

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res & 0xff);
						CHECK_FLAGB_UZ_LZ(res);

						//na(c) and or(c) always set C flag
						if ((op&3) == 1 || (op&3) == 2)
							SET_FLAG_C;

						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x4a:	//adb
				case 0x4b:	//sbb
					{
						UINT8 arg = read_op();
						UINT8 src = read_op();
						UINT16 res;

						if (op & 0x01)
							res = make_bcd_sub(READ_REG(arg), src);
						else
							res = make_bcd_add(READ_REG(arg), src);

						WRITE_REG(arg, res & 0xff);

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res & 0xff);
						CHECK_FLAGB_UZ_LZ(res);
						CHECK_FLAG_C(res, 0xff);

						check_optional_jr(arg);
						m_icount -= 3;
					}
					break;

				case 0x50:	//st
					{
						UINT8 arg = read_op();
						UINT8 src = read_op();
						UINT16 offset = REG_GET16(READ_SREG(arg));

						mem_writebyte(REG_UA>>4, offset, src);
						m_icount -= 8;
					}
					break;

				case 0x51:	//ld
					{
						UINT8 arg = read_op();
						UINT8 src = read_op();

						WRITE_REG(arg, src);
						m_icount -= 8;
					}
					break;

				case 0x52:	//stl
					{
						UINT8 arg = read_op();

						if (m_lcd_data_w)
							(*m_lcd_data_w)(*this, arg);

						m_icount -= 12;
					}
					break;

				case 0x54:	//ppo/pfl
					{
						UINT8 arg = read_op();
						UINT8 src = read_op();

						if (arg & 0x40)
						{
							m_flags = (m_flags & 0x0f) | (src & 0xf0);
						}
						else
						{
							if (m_lcd_control)
								(*m_lcd_control)(*this, src);
						}

						m_icount -= 3;
					}
					break;

				case 0x55:	//psr
					{
						UINT8 arg = read_op();
						WRITE_SREG(arg, arg&0x1f);

						m_icount -= 3;
					}
					break;

				case 0x56:	//pst
				case 0x57:	//pst
					{
						UINT8 arg = read_op();
						UINT8 src = read_op();
						UINT8 idx = GET_REG_IDX(op, arg);

						switch (idx)
						{
							case 0:		//PE
							case 1:		//PD
								WRITE_REG8(idx, src);
								if (m_port_w)
									(*m_port_w)(*this, REG_PD & REG_PE);
								break;
							case 2:		//IB
								REG_IB = (REG_IB & 0x1f) | (src & 0xe0);
								break;
							case 3:		//UA
								WRITE_REG8(idx, src);
								break;
							case 4:		//IA
								if (m_kb_w)
									(*m_kb_w)(*this, src);
								WRITE_REG8(idx, src);
								break;
							case 5:		//IE
								REG_IB &= (((src>>3)&0x1f) | 0xe0);
								m_irq_status &= ((src>>3)&0x1f);
								WRITE_REG8(idx, src);
								break;
							case 6:		//TM
							case 7:		//TM
								// read-only
								break;
						}

						m_icount -= 3;
					}
					break;

				case 0x58:	//bups
				case 0x59:	//bdns
					{
						UINT8 arg = read_op();
						UINT8 tmp;
						UINT16 res;

						for(;;)
						{
							tmp = mem_readbyte(REG_UA>>4, REG_IX);
							mem_writebyte(REG_UA>>6, REG_IZ, tmp);

							res = tmp - arg;
							if (REG_IX == REG_IY || !res)
								break;

							REG_IX += ((op&1) ? -1 : +1);
							REG_IZ += ((op&1) ? -1 : +1);
							m_icount -= 6;
						}

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res & 0xff);
						CHECK_FLAGB_UZ_LZ(res);
						CHECK_FLAG_C(res, 0xff);

						m_icount -= 9;
					}
					break;

				case 0x5c:	//sup
				case 0x5d:	//sdn
					{
						UINT8 arg = read_op();
						UINT16 res;

						for(;;)
						{
							res = mem_readbyte(REG_UA>>4, REG_IX) - arg;

							if (REG_IX == REG_IY || !res)
								break;

							REG_IX += ((op&1) ? -1 : +1);
							m_icount -= 6;
						}

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res & 0xff);
						CHECK_FLAGB_UZ_LZ(res);
						CHECK_FLAG_C(res, 0xff);

						m_icount -= 9;
					}
					break;

				case 0x60:	//st
				case 0x62:	//sti
					{
						UINT8 arg = read_op();
						UINT16 prev_ir = REG_IX;
						REG_IX += get_sign_im8(arg);

						mem_writebyte(REG_UA>>4, REG_IX++, READ_REG(arg));

						RESTORE_REG(op, REG_IX, prev_ir);

						m_icount -= 8;
					}
					break;

				case 0x61:	//st
				case 0x63:	//sti
					{
						UINT8 arg = read_op();
						UINT16 prev_ir = REG_IZ;
						REG_IZ += get_sign_im8(arg);

						mem_writebyte(REG_UA>>6, REG_IZ++, READ_REG(arg));

						RESTORE_REG(op, REG_IZ, prev_ir);
						m_icount -= 8;
					}
					break;

				case 0x64:	//std
					{
						UINT8 arg = read_op();
						REG_IX += get_sign_im8(arg);

						mem_writebyte(REG_UA>>4, REG_IX, READ_REG(arg));
						m_icount -= 6;
					}
					break;

				case 0x65:	//std
					{
						UINT8 arg = read_op();
						REG_IZ += get_sign_im8(arg);

						mem_writebyte(REG_UA>>6, REG_IZ, READ_REG(arg));
						m_icount -= 6;
					}
					break;

				case 0x68:	//ld
				case 0x6a:	//ldi
					{
						UINT8 arg = read_op();
						UINT16 prev_ir = REG_IX;
						REG_IX += get_sign_im8(arg);

						WRITE_REG(arg, mem_readbyte(REG_UA>>4, REG_IX++));

						RESTORE_REG(op, REG_IX, prev_ir);
						m_icount -= 8;
					}
					break;

				case 0x69:	//ld
				case 0x6b:	//ldi
					{
						UINT8 arg = read_op();
						UINT16 prev_ir = REG_IZ;
						REG_IZ += get_sign_im8(arg);

						WRITE_REG(arg, mem_readbyte(REG_UA>>6, REG_IZ++));

						RESTORE_REG(op, REG_IZ, prev_ir);
						m_icount -= 8;
					}
					break;

				case 0x6c:	//ldd
					{
						UINT8 arg = read_op();
						REG_IX += get_sign_im8(arg);

						WRITE_REG(arg, mem_readbyte(REG_UA>>4, REG_IX));
						m_icount -= 6;
					}
					break;

				case 0x6d:	//ldd
					{
						UINT8 arg = read_op();
						REG_IZ += get_sign_im8(arg);

						WRITE_REG(arg, mem_readbyte(REG_UA>>6, REG_IZ));
						m_icount -= 6;
					}
					break;

				case 0x70:	//cal z
				case 0x71:	//cal nc
				case 0x72:	//cal lz
				case 0x73:	//cal uz
				case 0x74:	//cal nz
				case 0x75:	//cal c
				case 0x76:	//cal nlz
				case 0x77:	//unconditional cal
					{
						UINT8 lsb = read_op();
						if (m_pc < INT_ROM) read_op();
						UINT8 msb = read_op();

						if (check_cond(op))
						{
							m_pc--;
							push(REG_SS, (m_pc>>8)&0xff);
							push(REG_SS, (m_pc>>0)&0xff);

							set_pc((msb<<8) | lsb);
							m_icount -= 6;
						}
						m_icount -= 3;
					}
					break;

				case 0x78:	//adc
				case 0x7a:	//sbc
				case 0x7c:	//ad
				case 0x7e:	//sb
					{
						UINT8 arg = read_op();
						UINT16 offset = REG_IX + get_sign_im8(arg);
						UINT8 src = mem_readbyte(REG_UA>>4, offset);

						UINT16 res = src + ((op & 2) ? -READ_REG(arg) : +READ_REG(arg)) ;

						if ((op & 4))
							mem_writebyte(REG_UA>>4, offset, res & 0xff);

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res & 0xff);
						CHECK_FLAGB_UZ_LZ(res);
						CHECK_FLAG_C(res, 0xff);

						m_icount -= 9;
					}
					break;

				case 0x79:	//adc
				case 0x7b:	//sbc
				case 0x7d:	//ad
				case 0x7f:	//sb
					{
						UINT8 arg = read_op();
						UINT16 offset = REG_IZ + get_sign_im8(arg);
						UINT8 src = mem_readbyte(REG_UA>>6, offset);

						UINT16 res = src + ((op & 2) ? -READ_REG(arg) : +READ_REG(arg)) ;

						if ((op & 4))
							mem_writebyte(REG_UA>>6, offset, res & 0xff);

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res & 0xff);
						CHECK_FLAGB_UZ_LZ(res);
						CHECK_FLAG_C(res, 0xff);

						m_icount -= 9;
					}
					break;

				case 0x80:	//adcw
				case 0x81:	//sbcw
				case 0x88:	//adw
				case 0x89:	//sbw
					{
						UINT8 arg = read_op();
						UINT8 src = get_sir_im8(arg);
						UINT32 res = REG_GET16(arg) + ((op & 0x01) ? -REG_GET16(src) : +REG_GET16(src));

						if (op & 0x08)	REG_PUT16(arg, res&0xffff);

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res & 0xffff);
						CHECK_FLAGW_UZ_LZ(res);
						CHECK_FLAG_C(res, 0xffff);

						check_optional_jr(arg);
						m_icount -= 8;
					}
					break;

				case 0x82:	//ldw
					{
						UINT8 arg = read_op();
						UINT8 src = get_sir_im8(arg);

						COPY_REG(arg, src);
						COPY_REG(arg+1, src+1);

						check_optional_jr(arg);
						m_icount -= 8;
					}
					break;

				case 0x84:	//ancw
				case 0x85:	//nacw
				case 0x86:	//orcw
				case 0x87:	//xrcw
				case 0x8c:	//anw
				case 0x8d:	//naw
				case 0x8e:	//orw
				case 0x8f:	//xrw
					{
						UINT8 arg = read_op();
						UINT8 src = get_sir_im8(arg);

						UINT8 res0 = make_logic(op, READ_REG(arg), READ_REG(src));
						COND_WRITE_REG(op, arg, res0);

						UINT8 res1 = make_logic(op, READ_REG(arg+1), READ_REG(src+1));
						COND_WRITE_REG(op, arg+1, res1);

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res0 || res1);
						CHECK_FLAGB_UZ_LZ(res1);

						//na(c) and or(c) always set C flag
						if ((op&3) == 1 || (op&3) == 2)
							SET_FLAG_C;

						check_optional_jr(arg);
						m_icount -= 8;
					}
					break;

				case 0x8a:	//adbw
				case 0x8b:	//sbbw
					{
						UINT8 arg = read_op();
						UINT8 src = get_sir_im8(arg);
						UINT16 res0, res1;

						if (op & 0x01)
							res0 = make_bcd_sub(READ_REG(arg), READ_REG(src));
						else
							res0 = make_bcd_add(READ_REG(arg), READ_REG(src));

						WRITE_REG(arg, res0 & 0xff);

						res1 = (res0>0xff) ? 1 : 0 ;

						if (op & 0x01)
							res1 = make_bcd_sub(READ_REG(arg+1), READ_REG(src+1) + res1);
						else
							res1 = make_bcd_add(READ_REG(arg+1), READ_REG(src+1) + res1);

						WRITE_REG(arg+1, res1 & 0xff);

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res0 || res1);
						CHECK_FLAGB_UZ_LZ(res1);
						CHECK_FLAG_C(res1, 0xff);

						check_optional_jr(arg);
						m_icount -= 8;
					}
					break;

				case 0x90:	//stw
					{
						UINT8 arg = read_op();
						UINT8 src = get_sir_im8(arg);
						UINT16 offset = REG_GET16(src);

						mem_writebyte(REG_UA>>4, offset+0, READ_REG(arg+0));
						mem_writebyte(REG_UA>>4, offset+1, READ_REG(arg+1));

						check_optional_jr(arg);
						m_icount -= 11;
					}
					break;

				case 0x91:	//ldw
					{
						UINT8 arg = read_op();
						UINT8 src = get_sir_im8(arg);
						UINT16 offset = REG_GET16(src);

						WRITE_REG(arg+0, mem_readbyte(REG_UA>>4, offset+0));
						WRITE_REG(arg+1, mem_readbyte(REG_UA>>4, offset+1));

						check_optional_jr(arg);
						m_icount -= 11;
					}
					break;

				case 0x92:	//stlw
					{
						UINT8 arg = read_op();

						if (m_lcd_data_w)
						{
							(*m_lcd_data_w)(*this, READ_REG(arg));
							(*m_lcd_data_w)(*this, READ_REG(arg+1));
						}

						check_optional_jr(arg);
						m_icount -= 19;
					}
					break;

				case 0x93:	//ldcw
					{
						UINT8 arg = read_op();
						UINT8 reg0, reg1;

						if (m_lcd_data_r)
						{
							reg0 = (*m_lcd_data_r)(*this);
							reg1 = (*m_lcd_data_r)(*this);
						}
						else
							reg0 = reg1 = 0xff;

						WRITE_REG(arg+0, reg0);
						WRITE_REG(arg+1, reg1);

						check_optional_jr(arg);
						m_icount -= 19;
					}
					break;

				case 0x96:	//pre
				case 0x97:	//pre
					{
						UINT8 arg = read_op();
						UINT8 idx = GET_REG_IDX(op, arg);

						if (idx < 5)
							m_reg16bit[idx] = REG_GET16(arg);

						check_optional_jr(arg);
						m_icount -= 8;
					}
					break;

				case 0x98:	//rodw
					{
						UINT8 arg = read_op();
						UINT8 op1 = (arg>>5) & 0x03;
						switch (op1)
						{
							case 0x00:	//rodw
							case 0x02:	//bidw
								{
									UINT16 src = REG_GET16(arg-1);
									UINT16 res = (src>>1)&0x7fff;

									if (!(op1&0x02))
										res = res | ((m_flags&FLAG_C) !=0 )<<15;

									REG_PUT16(arg-1, res);

									CLEAR_FLAGS;
									CHECK_FLAG_Z(res & 0xffff);
									CHECK_FLAGB_UZ_LZ(res);
									if (src&0x01) SET_FLAG_C;
								}
								break;

							case 0x01:	//rouw
							case 0x03:	//biuw
								{
									UINT16 src = REG_GET16(arg);
									UINT16 res = (src<<1)&0xfffe;

									if (!(op1&0x02))
										res = res | ((m_flags&FLAG_C) !=0 )<<0;

									REG_PUT16(arg, res);

									CLEAR_FLAGS;
									CHECK_FLAG_Z(res & 0xffff);
									CHECK_FLAGW_UZ_LZ(res);
									if (src&0x8000) SET_FLAG_C;
								}
								break;
						}

						check_optional_jr(arg);
						m_icount -= 11;
					}
					break;

				case 0x9a:
					{
						UINT8 arg = read_op();
						UINT8 op1 = (arg>>5) & 0x03;
						switch (op1)
						{
							case 0x00:	//didw
								{
									UINT16 src = (REG_GET16(arg-1)>>4)&0x0fff;
									REG_PUT16(arg-1, src);

									CLEAR_FLAGS;
									CHECK_FLAG_Z(src & 0xffff);
									CHECK_FLAGB_UZ_LZ(src);
								}
								break;

							case 0x01:	//diuw
								{
									UINT16 src = (REG_GET16(arg)<<4)&0xfff0;
									REG_PUT16(arg, src);

									CLEAR_FLAGS;
									CHECK_FLAG_Z(src & 0xffff);
									CHECK_FLAGW_UZ_LZ(src);
								}
								break;

							case 0x02:	//bydw
								{
									UINT8 src = READ_REG(arg);

									WRITE_REG(arg, 0);
									WRITE_REG(arg-1, src);

									CLEAR_FLAGS;
									CHECK_FLAG_Z(src & 0xff);
									CHECK_FLAGB_UZ_LZ(src);
								}
								break;

							case 0x03:	//byuw
								{
									UINT8 src = READ_REG(arg);

									WRITE_REG(arg, 0);
									WRITE_REG(arg+1, src);

									CLEAR_FLAGS;
									CHECK_FLAG_Z(src & 0xff);
									CHECK_FLAGB_UZ_LZ(src);
								}
								break;
						}

						check_optional_jr(arg);
						m_icount -= 11;
					}
					break;

				case 0x9b:	//cmpw/invw
					{
						UINT8 arg = read_op();
						UINT16 res = ~(REG_GET16(arg));
						if (!(arg & 0x40)) res++;

						REG_PUT16(arg, res);

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res & 0xffff);
						CHECK_FLAGW_UZ_LZ(res);

						if (res || (arg & 0x40)) SET_FLAG_C;

						check_optional_jr(arg);
						m_icount -= 8;
					}
					break;

				case 0x9c:	//gpow/gflw
					{
						UINT8 arg = read_op();
						UINT8 reg0, reg1;

						if (arg&0x40)
						{
							reg0 = reg1 = m_flags;
						}
						else
						{
							if (m_port_r)
							{
								reg0 = (*m_port_r)(*this);
								reg1 = (*m_port_r)(*this);
							}
							else
								reg0 = reg1 = 0xff;

							reg0&=(~REG_PE);
							reg1&=(~REG_PE);

						}

						WRITE_REG(arg+0, reg0);
						WRITE_REG(arg+1, reg1);

						check_optional_jr(arg);
						m_icount -= 8;
					}
					break;

				case 0x9e:	//gre
				case 0x9f:	//gre
					{
						UINT8 arg = read_op();
						UINT8 idx = GET_REG_IDX(op, arg);
						UINT16 src;

						if (idx >= 5)
						{
							UINT16 port = 0xff;

							if (m_kb_r)
								port = (*m_kb_r)(*this);

							src = (REG_KY & 0x0f00) | (port & 0xf0ff);
						}
						else
							src = m_reg16bit[idx];

						REG_PUT16(arg, src);

						check_optional_jr(arg);
						m_icount -= 8;
					}
					break;

				case 0xa0:	//stw
				case 0xa2:	//stiw
					{
						UINT8 arg = read_op();
						UINT16 prev_ir = REG_IX;
						UINT8 ir_inc = READ_REG(get_sir_im8(arg));

						REG_IX += ((arg & 0x80) ? -ir_inc : +ir_inc);

						mem_writebyte(REG_UA>>4, REG_IX++, READ_REG(arg+0));
						mem_writebyte(REG_UA>>4, REG_IX++, READ_REG(arg+1));

						RESTORE_REG(op, REG_IX, prev_ir);
						m_icount -= 11;
					}
					break;

				case 0xa1:	//stw
				case 0xa3:	//stiw
					{
						UINT8 arg = read_op();
						UINT16 prev_ir = REG_IZ;
						UINT8 ir_inc = READ_REG(get_sir_im8(arg));

						REG_IZ += ((arg & 0x80) ? -ir_inc : +ir_inc);

						mem_writebyte(REG_UA>>6, REG_IZ++, READ_REG(arg+0));
						mem_writebyte(REG_UA>>6, REG_IZ++, READ_REG(arg+1));

						RESTORE_REG(op, REG_IZ, prev_ir);
						m_icount -= 11;
					}
					break;

				case 0xa4:	//stdw
					{
						UINT8 arg = read_op();
						UINT8 ir_inc = READ_REG(get_sir_im8(arg));

						REG_IX += ((arg & 0x80) ? -ir_inc : +ir_inc);

						mem_writebyte(REG_UA>>4, REG_IX--, READ_REG(arg-0));
						mem_writebyte(REG_UA>>4, REG_IX, READ_REG(arg-1));

						m_icount -= 9;
					}
					break;
				case 0xa5:	//stdw
					{
						UINT8 arg = read_op();
						UINT8 ir_inc = READ_REG(get_sir_im8(arg));

						REG_IZ += ((arg & 0x80) ? -ir_inc : +ir_inc);

						mem_writebyte(REG_UA>>6, REG_IZ--, READ_REG(arg-0));
						mem_writebyte(REG_UA>>6, REG_IZ, READ_REG(arg-1));

						m_icount -= 9;
					}
					break;

				case 0xa6:	//phsw
					{
						UINT8 arg = read_op();
						push(REG_SS, READ_REG(arg));
						push(REG_SS, READ_REG(arg-1));

						m_icount -= 12;
					}
					break;
				case 0xa7:	//phuw
					{
						UINT8 arg = read_op();
						push(REG_US, READ_REG(arg));
						push(REG_US, READ_REG(arg-1));

						m_icount -= 12;
					}
					break;

				case 0xa8:	//ldw
				case 0xaa:	//ldiw
					{
						UINT8 arg = read_op();
						UINT16 prev_ir = REG_IX;
						UINT8 ir_inc = READ_REG(get_sir_im8(arg));

						REG_IX += ((arg & 0x80) ? -ir_inc : +ir_inc);

						WRITE_REG(arg+0, mem_readbyte(REG_UA>>4, REG_IX++));
						WRITE_REG(arg+1, mem_readbyte(REG_UA>>4, REG_IX++));

						RESTORE_REG(op, REG_IX, prev_ir);

						m_icount -= 11;
					}
					break;

				case 0xa9:	//ldw
				case 0xab:	//ldiw
					{
						UINT8 arg = read_op();
						UINT16 prev_ir = REG_IZ;
						UINT8 ir_inc = READ_REG(get_sir_im8(arg));

						REG_IZ += ((arg & 0x80) ? -ir_inc : +ir_inc);

						WRITE_REG(arg+0, mem_readbyte(REG_UA>>6, REG_IZ++));
						WRITE_REG(arg+1, mem_readbyte(REG_UA>>6, REG_IZ++));

						RESTORE_REG(op, REG_IZ, prev_ir);

						m_icount -= 11;
					}
					break;

				case 0xac:	//lddw
					{
						UINT8 arg = read_op();
						UINT8 ir_inc = READ_REG(get_sir_im8(arg));

						REG_IX += ((arg & 0x80) ? -ir_inc : +ir_inc);

						WRITE_REG(arg-0, mem_readbyte(REG_UA>>4, REG_IX--));
						WRITE_REG(arg-1, mem_readbyte(REG_UA>>4, REG_IX));

						m_icount -= 9;
					}
					break;

				case 0xad:	//lddw
					{
						UINT8 arg = read_op();
						UINT8 ir_inc = READ_REG(get_sir_im8(arg));

						REG_IZ += ((arg & 0x80) ? -ir_inc : +ir_inc);

						WRITE_REG(arg-0, mem_readbyte(REG_UA>>6, REG_IZ--));
						WRITE_REG(arg-1, mem_readbyte(REG_UA>>6, REG_IZ));

						m_icount -= 9;
					}
					break;

				case 0xae:	//ppsw
				case 0xaf:	//ppuw
					{
						UINT8 arg = read_op();

						WRITE_REG(arg, pop((op&1) ? REG_US : REG_SS));
						WRITE_REG(arg+1, pop((op&1) ? REG_US : REG_SS));

						m_icount -= 14;
					}
					break;

				case 0xb0:	//jr z
				case 0xb1:	//jr nc
				case 0xb2:	//jr lz
				case 0xb3:	//jr uz
				case 0xb4:	//jr nz
				case 0xb5:	//jr c
				case 0xb6:	//jr nlz
				case 0xb7:	//unconditional jr
					{
						UINT8 arg = read_op();
						UINT32 new_pc = m_pc-1 + get_im_7(arg);

						if (check_cond(op))
							set_pc(new_pc);
						m_icount -= 3;
					}
					break;

				case 0xb8:	//adcw
				case 0xbc:	//adw
					{
						UINT8 arg = read_op();
						UINT8 ir_inc = READ_REG(get_sir_im8(arg));

						UINT16 offset = REG_IX + ((arg & 0x80) ? -ir_inc : +ir_inc);

						UINT16 src0 = mem_readbyte(REG_UA>>4, offset) + READ_REG(arg);
						UINT16 src1 = mem_readbyte(REG_UA>>4, offset+1) + READ_REG(arg+1) + ((src0>0xff) ? 1 : 0);

						if (op&0x04)
						{
							mem_writebyte(REG_UA>>4, offset+0, src0 & 0xff);
							mem_writebyte(REG_UA>>4, offset+1, src1 & 0xff);
						}

						CLEAR_FLAGS;
						CHECK_FLAGB_UZ_LZ(src1);
						CHECK_FLAG_Z(src0 || src1);
						CHECK_FLAG_C(src1, 0xff);

						m_icount -= 15;
					}
					break;

				case 0xba:	//sbcw
				case 0xbe:	//sbw
					{
						UINT8 arg = read_op();
						UINT8 ir_inc = READ_REG(get_sir_im8(arg));

						UINT16 offset = REG_IX + ((arg & 0x80) ? -ir_inc : +ir_inc);

						UINT16 src0 = mem_readbyte(REG_UA>>4, offset) - READ_REG(arg);
						UINT16 src1 = mem_readbyte(REG_UA>>4, offset+1) - READ_REG(arg+1) - ((src0>0xff) ? 1 : 0);

						if (op&0x04)
						{
							mem_writebyte(REG_UA>>4, offset+0, src0 & 0xff);
							mem_writebyte(REG_UA>>4, offset+1, src1 & 0xff);
						}

						CLEAR_FLAGS;
						CHECK_FLAGB_UZ_LZ(src1);
						CHECK_FLAG_Z(src0 || src1);
						CHECK_FLAG_C(src1, 0xff);

						m_icount -= 15;
					}
					break;

				case 0xb9:	//adcw
				case 0xbd:	//adw
					{
						UINT8 arg = read_op();
						UINT8 ir_inc = READ_REG(get_sir_im8(arg));

						UINT16 offset = REG_IZ + ((arg & 0x80) ? -ir_inc : +ir_inc);

						UINT16 src0 = mem_readbyte(REG_UA>>6, offset) + READ_REG(arg);
						UINT16 src1 = mem_readbyte(REG_UA>>6, offset+1) + READ_REG(arg+1) + ((src0>0xff) ? 1 : 0);

						if (op&0x04)
						{
							mem_writebyte(REG_UA>>6, offset+0, src0 & 0xff);
							mem_writebyte(REG_UA>>6, offset+1, src1 & 0xff);
						}

						CLEAR_FLAGS;
						CHECK_FLAGB_UZ_LZ(src1);
						CHECK_FLAG_Z(src0 || src1);
						CHECK_FLAG_C(src1, 0xff);

						m_icount -= 15;
					}
					break;

				case 0xbb:	//sbcw
				case 0xbf:	//sbw
					{
						UINT8 arg = read_op();
						UINT8 ir_inc = READ_REG(get_sir_im8(arg));

						UINT16 offset = REG_IZ + ((arg & 0x80) ? -ir_inc : +ir_inc);

						UINT16 src0 = mem_readbyte(REG_UA>>6, offset) - READ_REG(arg);
						UINT16 src1 = mem_readbyte(REG_UA>>6, offset+1) - READ_REG(arg+1) - ((src0>0xff) ? 1 : 0);

						if (op&0x04)
						{
							mem_writebyte(REG_UA>>6, offset+0, src0 & 0xff);
							mem_writebyte(REG_UA>>6, offset+1, src1 & 0xff);
						}

						CLEAR_FLAGS;
						CHECK_FLAGB_UZ_LZ(src1);
						CHECK_FLAG_Z(src0 || src1);
						CHECK_FLAG_C(src1, 0xff);

						m_icount -= 15;
					}
					break;

				case 0xc0:	//adbcm
				case 0xc1:	//sbbcm
				case 0xc8:	//adbm
				case 0xc9:	//sbbm
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();
						UINT8 dst = arg;
						UINT8 src = get_sir_im8(arg, arg1);
						UINT8 c, f;
						UINT16 res = 0;

						c = f = 0;
						for (int n=GET_IM3(arg1); n>0; n--)
						{
							if (op & 0x01)
								res = make_bcd_sub(READ_REG(dst), READ_REG(src) + c);
							else
								res = make_bcd_add(READ_REG(dst), READ_REG(src) + c);

							c = (res > 0xff) ? 1 : 0;

							COND_WRITE_REG(op, dst, res&0xff);

							f |= (res&0xff);
							dst++; src++;

							m_icount -= 5;
						}

						CLEAR_FLAGS;
						CHECK_FLAG_Z(f);
						CHECK_FLAGB_UZ_LZ(res);
						CHECK_FLAG_C(res, 0xff);

						check_optional_jr(arg);
						m_icount -= 2;
					}
					break;

				case 0xc2:	//ldm
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();
						UINT8 dst = arg;
						UINT8 src = get_sir_im8(arg, arg1);

						for (int n=GET_IM3(arg1); n>0; n--)
						{
							COPY_REG(dst++, src++);
							m_icount -= 5;
						}

						check_optional_jr(arg);
						m_icount -= 2;
					}
					break;

				case 0xc4:	//ancm
				case 0xc5:	//nacm
				case 0xc6:	//orcm
				case 0xc7:	//xrcm
				case 0xcc:	//anm
				case 0xcd:	//nam
				case 0xce:	//orm
				case 0xcf:	//xrm
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();
						UINT8 dst = arg;
						UINT8 src = get_sir_im8(arg, arg1);
						UINT8 res = 0, f = 0;

						for (int n=GET_IM3(arg1); n>0; n--)
						{
							res = make_logic(op, READ_REG(dst), READ_REG(src));

							COND_WRITE_REG(op, dst, res);

							f |= res;

							dst++; src++;

							m_icount -= 3;
						}

						CLEAR_FLAGS;
						CHECK_FLAG_Z(f);
						CHECK_FLAGB_UZ_LZ(res);

						//na(c) and or(c) always set C flag
						if ((op&3) == 1 || (op&3) == 2)
							SET_FLAG_C;

						check_optional_jr(arg);
					}
					break;

				case 0xca:	//adbm
				case 0xcb:	//sbbm
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();
						UINT8 dst = arg;
						UINT16 res = 0;
						UINT8 src, f;
						src = arg1 & 0x1f;
						f = 0;

						for (int n=GET_IM3(arg1); n>0; n--)
						{
							if (op & 0x01)
								res = make_bcd_sub(READ_REG(dst), src);
							else
								res = make_bcd_add(READ_REG(dst), src);

							src = (res > 0xff) ? 1 : 0;

							COND_WRITE_REG(op, dst, res&0xff);

							f |= (res&0xff);
							dst++;

							m_icount -= 5;
						}

						CLEAR_FLAGS;
						CHECK_FLAG_Z(f);
						CHECK_FLAGB_UZ_LZ(res);
						CHECK_FLAG_C(res, 0xff);

						check_optional_jr(arg);
						m_icount -= 2;
					}
					break;

				case 0xd0:	//stw
					{
						UINT8 arg = read_op();
						UINT16 offset = REG_GET16(READ_SREG(arg));

						mem_writebyte(REG_UA>>4, offset+0, read_op());
						mem_writebyte(REG_UA>>4, offset+1, read_op());

						m_icount -= 11;
					}
					break;

				case 0xd1:	//ldw
					{
						UINT8 arg = read_op();
						UINT8 reg0 = read_op();
						UINT8 reg1 = read_op();

						WRITE_REG(arg+0, reg0);
						WRITE_REG(arg+1, reg1);
						m_icount -= 11;
					}
					break;

				case 0xd2:	//stlm
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();

						for (int n=GET_IM3(arg1); n>0; n--)
						{
							if (m_lcd_data_w)
								(*m_lcd_data_w)(*this, READ_REG(arg));

							arg++;
							m_icount -= 8;
						}

						m_icount -= 3;
					}
					break;

				case 0xd3:	//ldlm
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();
						UINT8 src;

						for (int n=GET_IM3(arg1); n>0; n--)
						{
							if (m_lcd_data_r)
								src = (*m_lcd_data_r)(*this);
							else
								src = 0xff;

							WRITE_REG(arg, src++);

							m_icount -= 8;
						}

						m_icount -= 3;
					}
					break;

				case 0xd6:	//pre
				case 0xd7:	//pre
					{
						UINT8 arg = read_op();
						UINT8 lsb = read_op();
						UINT8 msb = read_op();
						UINT8 idx = GET_REG_IDX(op, arg);

						if (idx < 5)
							m_reg16bit[idx] = (msb<<8) | lsb;

						m_icount -= 8;
					}
					break;

				case 0xd8:	//bup
				case 0xd9:	//bdn
					{
						UINT8 src;
						for(;;)
						{
							src = mem_readbyte(REG_UA>>4, REG_IX);
							mem_writebyte(REG_UA>>6, REG_IZ, src);

							if (REG_IX == REG_IY)
								break;

							REG_IX += ((op&1) ? -1 : +1);
							REG_IZ += ((op&1) ? -1 : +1);
							m_icount -= 6;
						}

						m_icount -= 9;
					}
					break;

				case 0xda:
					{
						UINT8 arg = read_op();
						UINT8 op1 = (arg>>5) & 0x03;
						switch (op1)
						{
							case 0x00:	//didm
								{
									UINT8 arg1 = read_op();
									UINT8 r1 = 0, r2 = 0;

									for (int n=GET_IM3(arg1); n>0; n--)
									{
										r2 = r1;
										r1 = READ_REG(arg);
										r2 = ((r1>>4)&0x0f) | ((r2<<4)&0xf0);
										WRITE_REG(arg--, r2);
										m_icount -= 5;
									}

									CLEAR_FLAGS;
									CHECK_FLAGB_UZ_LZ(r2);
									CHECK_FLAG_Z(r2);
								}
								break;

							case 0x01:	//dium
								{
									UINT8 arg1 = read_op();
									UINT8 r1 = 0, r2 = 0;

									for (int n=GET_IM3(arg1); n>0; n--)
									{
										r2 = r1;
										r1 = READ_REG(arg);
										r2 = ((r1<<4)&0xf0) | ((r2>>4)&0x0f);
										WRITE_REG(arg++, r2);
										m_icount -= 5;
									}

									CLEAR_FLAGS;
									CHECK_FLAGB_UZ_LZ(r2);
									CHECK_FLAG_Z(r2);
								}
								break;

							case 0x02:	//bydm
								{
									UINT8 arg1 = read_op();
									UINT8 r1 = 0, r2 = 0, f = 0;

									for (int n=GET_IM3(arg1); n>0; n--)
									{
										r2 = r1;
										r1 = READ_REG(arg);
										WRITE_REG(arg--, r2);
										f |= r2;
										m_icount -= 5;
									}

									CLEAR_FLAGS;
									CHECK_FLAGB_UZ_LZ(r2);
									CHECK_FLAG_Z(f);
								}
								break;

							case 0x03:	//byum
								{
									UINT8 arg1 = read_op();
									UINT8 r1 = 0, r2 = 0, f = 0;

									for (int n=GET_IM3(arg1); n>0; n--)
									{
										r2 = r1;
										r1 = READ_REG(arg);
										WRITE_REG(arg++, r2);
										f |= r2;
										m_icount -= 5;
									}

									CLEAR_FLAGS;
									CHECK_FLAGB_UZ_LZ(r2);
									CHECK_FLAG_Z(f);
								}
								break;
						}
					}
					break;

				case 0xdb:	//cmpm/invm
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();
						UINT8 r1 = 0, r2 = 0, f = 0;

						r2 = (arg&0x40) ? 0 : 1;

						for (int n=GET_IM3(arg1); n>0; n--)
						{
							r1 = r2 + (~READ_REG(arg));
							WRITE_REG(arg++, r1);
							if (r1) r2 = 0;

							f |= r1;

							m_icount -= 5;
						}

						CLEAR_FLAGS;
						CHECK_FLAG_Z(f);
						CHECK_FLAGB_UZ_LZ(r1);
						if (f != 0 || (arg & 0x40))
							SET_FLAG_C;
					}
					break;

				case 0xdc:	//sup
				case 0xdd:	//sdn
					{
						UINT8 arg = read_op();
						UINT16 res;

						for(;;)
						{
							res = mem_readbyte(REG_UA>>4, REG_IX) - READ_REG(arg);

							if (REG_IX == REG_IY || !res)
								break;

							REG_IX += ((op&1) ? -1 : +1);
							m_icount -= 6;
						}

						CLEAR_FLAGS;
						CHECK_FLAG_Z(res & 0xff);
						CHECK_FLAGB_UZ_LZ(res);
						CHECK_FLAG_C(res, 0xff);

						m_icount -= 9;
					}
					break;

				case 0xde:	//jp
					{
						UINT8 arg = read_op();
						set_pc(REG_GET16(arg));

						m_icount -= 5;
					}
					break;

				case 0xdf:	//jp
					{
						UINT8 arg = read_op();
						UINT16 offset = REG_GET16(arg);
						UINT8 lsb = mem_readbyte(REG_UA>>4, offset+0);
						UINT8 msb = mem_readbyte(REG_UA>>4, offset+1);

						set_pc((msb<<8) | lsb);

						m_icount -= 5;
					}
					break;

				case 0xe0:	//stm
				case 0xe2:	//stim
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();
						UINT16 prev_ir = REG_IX;
						UINT8 ir_inc = READ_REG(get_sir_im8(arg, arg1));

						REG_IX += ((arg & 0x80) ? -ir_inc : +ir_inc);

						for (int n=GET_IM3(arg1); n>0; n--)
						{
							mem_writebyte(REG_UA>>4, REG_IX++, READ_REG(arg++));
							m_icount -= 3;
						}

						RESTORE_REG(op, REG_IX, prev_ir);

						m_icount -= 5;
					}
					break;

				case 0xe1:	//stm
				case 0xe3:	//stim
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();
						UINT16 prev_ir = REG_IZ;
						UINT8 ir_inc = READ_REG(get_sir_im8(arg, arg1));

						REG_IZ += ((arg & 0x80) ? -ir_inc : +ir_inc);

						for (int n=GET_IM3(arg1); n>0; n--)
						{
							mem_writebyte(REG_UA>>6, REG_IZ++, READ_REG(arg++));
							m_icount -= 3;
						}

						RESTORE_REG(op, REG_IZ, prev_ir);

						m_icount -= 5;
					}
					break;

				case 0xe4:	//stdm
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();
						UINT8 ir_inc = READ_REG(get_sir_im8(arg, arg1));

						REG_IX += ((arg & 0x80) ? -ir_inc : +ir_inc);

						for (int n=GET_IM3(arg1); n>0; n--)
						{
							mem_writebyte(REG_UA>>4, REG_IX--, READ_REG(arg--));
							m_icount -= 3;
						}

						REG_IX++;//todo

						m_icount -= 3;
					}
					break;

				case 0xe5:	//stdm
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();
						UINT8 ir_inc = READ_REG(get_sir_im8(arg, arg1));

						REG_IZ += ((arg & 0x80) ? -ir_inc : +ir_inc);

						for (int n=GET_IM3(arg1); n>0; n--)
						{
							mem_writebyte(REG_UA>>6, REG_IZ--, READ_REG(arg--));
							m_icount -= 3;
						}

						REG_IZ++;

						m_icount -= 3;
					}
					break;

				case 0xe6:	//phsm
				case 0xe7:	//phum
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();

						for (int n=GET_IM3(arg1); n>0; n--)
						{
							push((op&1) ? REG_US : REG_SS, READ_REG(arg--));

							m_icount -= 3;
						}

						m_icount -= 3;
					}
					break;

				case 0xe8:	//ldm
				case 0xea:	//ldim
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();
						UINT16 prev_ir = REG_IX;
						UINT8 ir_inc = READ_REG(get_sir_im8(arg, arg1));

						REG_IX += ((arg & 0x80) ? -ir_inc : +ir_inc);

						for (int n=GET_IM3(arg1); n>0; n--)
						{
							WRITE_REG(arg++, mem_readbyte(REG_UA>>4, REG_IX++));
							m_icount -= 3;
						}

						RESTORE_REG(op, REG_IX, prev_ir);

						m_icount -= 5;
					}
					break;

				case 0xe9:	//ldm
				case 0xeb:	//ldim
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();
						UINT16 prev_ir = REG_IZ;
						UINT8 ir_inc = READ_REG(get_sir_im8(arg, arg1));

						REG_IZ += ((arg & 0x80) ? -ir_inc : +ir_inc);

						for (int n=GET_IM3(arg1); n>0; n--)
						{
							WRITE_REG(arg++, mem_readbyte(REG_UA>>6, REG_IZ++));
							m_icount -= 3;
						}

						RESTORE_REG(op, REG_IZ, prev_ir);

						m_icount -= 5;
					}
					break;

				case 0xec:	//lddm
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();
						UINT8 ir_inc = READ_REG(get_sir_im8(arg, arg1));

						REG_IX += ((arg & 0x80) ? -ir_inc : +ir_inc);

						for (int n=GET_IM3(arg1); n>0; n--)
						{
							WRITE_REG(arg--, mem_readbyte(REG_UA>>4, REG_IX--));
							m_icount -= 3;
						}

						REG_IX++;

						m_icount -= 3;
					}
					break;

				case 0xed:	//lddm
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();
						UINT8 ir_inc = READ_REG(get_sir_im8(arg, arg1));

						REG_IZ += ((arg & 0x80) ? -ir_inc : +ir_inc);

						for (int n=GET_IM3(arg1); n>0; n--)
						{
							WRITE_REG(arg--, mem_readbyte(REG_UA>>6, REG_IZ--));
							m_icount -= 3;
						}

						REG_IZ++;

						m_icount -= 3;
					}
					break;

				case 0xee:	//ppsm
				case 0xef:	//ppum
					{
						UINT8 arg = read_op();
						UINT8 arg1 = read_op();

						for (int n=GET_IM3(arg1); n>0; n--)
						{
							WRITE_REG(arg++, pop((op&1) ? REG_US : REG_SS));
							m_icount -= 3;
						}

						m_icount -= 5;
					}
					break;

				case 0xf0:	//rtn z
				case 0xf1:	//rtn nc
				case 0xf2:	//rtn lz
				case 0xf3:	//rtn uz
				case 0xf4:	//rtn nz
				case 0xf5:	//rtn c
				case 0xf6:	//rtn nlz
				case 0xf7:	//unconditional rtn
					{
						if (check_cond(op))
						{
							UINT8 lsb = pop(REG_SS) ;
							UINT8 msb = pop(REG_SS);

							set_pc((((msb<<8) | (lsb<<0)) + 1));
						}
						m_icount -= 3;
					}
					break;

				case 0xf8:	//nop
						m_icount -= 3;
					break;

				case 0xf9:	//clt
						REG_TM = 0;
						m_icount -= 3;
					break;

				case 0xfa:	//fst
						m_state |= CPU_FAST;
						m_icount -= 3;
					break;

				case 0xfb:	//slw
						m_state &= ~CPU_FAST;
						m_icount -= 3;
					break;

				case 0xfd:	//rtni
					{
						UINT8 lsb = pop(REG_SS);
						UINT8 msb = pop(REG_SS);

						set_pc((msb<<8) | (lsb<<0));

						m_icount -= 5;
					}
					//fall through

				case 0xfc:	//cani
					{
						for (UINT8 arg=0x10; arg>0; arg>>=1)
						{
							if (REG_IB & arg)
							{
								REG_IB &= (~arg);
								m_irq_status &= (~arg);
								break;
							}
						}

						m_icount -= 3;
					}
					break;

				case 0xfe:	//off
					{
						set_pc(0);
						REG_UA = REG_IA = 0;
						REG_IX = REG_IY = REG_IZ = 0;
						REG_PE = 0;
						REG_IE = (REG_IE&0x0c) | ((REG_IB>>1) & 0x10);
						REG_IB &= 0xe3;
						if (m_flags & FLAG_SW)
							m_flags |= FLAG_APO;
						else
							m_flags &= ~FLAG_APO;

						m_state |= CPU_SLP;

						m_irq_status = 0;
						if (m_lcd_control)
							(*m_lcd_control)(*this, 0);

						if (m_kb_w)
							(*m_kb_w)(*this, 0);
						m_icount -= 3;
					}
					break;

				case 0xff:	//trp
					{
						m_pc--;
						push(REG_SS, (m_pc>>8)&0xff);
						push(REG_SS, (m_pc>>0)&0xff);
						set_pc(0x0022);
						m_icount -= 9;
					}
					break;

				case 0x03:
				case 0x19:
				case 0x43:
				case 0x53:
				case 0x5a:
				case 0x5b:
				case 0x5e:
				case 0x5f:
				case 0x66:
				case 0x67:
				case 0x6e:
				case 0x6f:
				case 0x83:
				case 0x94:
				case 0x95:
				case 0x99:
				case 0x9d:
				case 0xc3:
				case 0xd4:
				case 0xd5:
					logerror( "%06x: illegal instruction %02x encountered\n", m_pc, op );
					break;

				default:
					logerror( "%06x: unimplemented instruction %02x encountered\n", m_pc, op );
					break;
			}
		}

		//if is in the internal ROM align the pc
		if ((m_fetch_addr&1) && m_pc < INT_ROM)
			set_pc((m_fetch_addr+1)>>1);

		m_icount -= 3;
	} while (m_icount > 0);
}


//-------------------------------------------------
//  execute_set_input
//-------------------------------------------------

void hd61700_cpu_device::execute_set_input(int inputnum, int state)
{
	switch (inputnum)
	{
		case INPUT_LINE_RESET:
			REG_UA = 0;
			REG_IA = 0;
			REG_IX = 0;
			REG_IY = 0;
			REG_IZ = 0;
			REG_PE = 0;
			REG_IE = 0;
			REG_IB = 0;
			m_state &= ~(CPU_SLP | CPU_FAST);
			set_pc(0x0000);
			break;
		case HD61700_KEY_INT:	//level sensitive line
			if (((REG_IE>>3) & (1<<inputnum)) && state != CLEAR_LINE)
				REG_IB |= (1<<inputnum);
			break;

		case HD61700_INT1:	//edge sensitive line
			if (((REG_IE>>3) & (1<<inputnum)) && (m_lines_status[inputnum] != state))
				REG_IB |= (1<<inputnum);

			if (m_lines_status[inputnum] == CLEAR_LINE && state != CLEAR_LINE)
				REG_IE = (REG_IE & 0xfd) | 0x02;	//rising edge
			else if (m_lines_status[inputnum] != CLEAR_LINE && state == CLEAR_LINE)
				REG_IE = (REG_IE & 0xfd) | 0x00;	//falling edge

			REG_KY = (REG_KY & 0xf7ff) | ((state != CLEAR_LINE)<<11);
			break;
		case HD61700_INT2:	//level sensitive line
			if (((REG_IE>>3) & (1<<inputnum)) && state != CLEAR_LINE)
				REG_IB |= (1<<inputnum);

			REG_IE = (REG_IE & 0xfe) | (state != CLEAR_LINE);
			REG_KY = (REG_KY & 0xfbff) | ((state != CLEAR_LINE)<<10);
			break;
		case HD61700_ON_INT:	//level sensitive line
			if ((REG_IE>>3) & (1<<inputnum) && state != CLEAR_LINE)
				REG_IB |= (1<<inputnum);

			REG_KY = (REG_KY & 0xfdff) | ((state != CLEAR_LINE)<<9);
			break;

		case HD61700_SW:	//level sensitive line
			if (state != CLEAR_LINE)
			{
				if ((m_state & CPU_SLP) || m_lines_status[HD61700_SW] == CLEAR_LINE)
				{
					m_state &= ~(CPU_SLP | CPU_FAST);
					m_flags &= ~FLAG_APO;
					set_pc(0x0001);
				}
			}

			m_flags |= ((state != CLEAR_LINE)<<3);
			break;
	}

	m_lines_status[inputnum] = state;
}


//**************************************************************************
//  INLINE HELPERS
//**************************************************************************

inline void hd61700_cpu_device::set_pc(INT32 new_pc)
{
	m_curpc = (m_curpc & 0x30000) | new_pc;
	m_pc = new_pc & 0xffff;
	m_fetch_addr = new_pc<<1;
}

inline UINT8 hd61700_cpu_device::read_op()
{
	UINT16 data = 0;
	UINT32 addr18 = make_18bit_addr((m_irq_status) ? 0 : prev_ua, m_pc);

	if (m_pc <= INT_ROM)
	{
		data = m_program->read_word(addr18<<1);

		if (!(m_fetch_addr&1))
			data = (data>>8) ;
	}
	else
	{
		if (m_fetch_addr&1)
			data = m_program->read_word((addr18+1)<<1);
		else
			data = m_program->read_word((addr18+0)<<1);
	}

	m_fetch_addr += ((m_pc > INT_ROM) ? 2 : 1);

	m_pc = m_fetch_addr>>1;

	m_curpc =  make_18bit_addr((m_irq_status) ? 0 : prev_ua, m_pc);

	prev_ua = REG_UA;

	return (data&0xff);
}

inline UINT8 hd61700_cpu_device::mem_readbyte(UINT8 segment, UINT16 offset)
{
	return m_program->read_word(make_18bit_addr(segment, offset)<<1) & 0xff;
}

inline void hd61700_cpu_device::mem_writebyte(UINT8 segment, UINT16 offset, UINT8 data)
{
	m_program->write_word(make_18bit_addr(segment, offset)<<1, data);
}

inline UINT32 hd61700_cpu_device::make_18bit_addr(UINT8 segment, UINT16 offset)
{
	if (offset >= ((REG_IB>>6) & 0x03) * 0x4000)
		return (UINT32)((offset | ((segment&0x03)<<16)) & 0x3ffff);
	else
		return offset;
}

inline void hd61700_cpu_device::push(UINT16 &offset, UINT8 data)
{
	offset--;
	mem_writebyte(REG_UA>>2, offset, data);
}

inline UINT8 hd61700_cpu_device::pop(UINT16 &offset)
{
	UINT8 data = mem_readbyte(REG_UA>>2, offset);
	offset++;
	return data;
}

inline int hd61700_cpu_device::check_cond(UINT32 op)
{
	switch ( op & 0x07 )
	{
	case 0x00:	// Z set
		if ( !(m_flags & FLAG_Z) )
			return 1;
		break;

	case 0x01:	// NC set
		if ( !(m_flags & FLAG_C) )
			return 1;
		break;

	case 0x02:	// LZ set
		if ( !(m_flags & FLAG_LZ) )
			return 1;
		break;

	case 0x03:	// UZ set
		if ( !(m_flags & FLAG_UZ) )
			return 1;
		break;

	case 0x04:	// NZ set
		if ( m_flags & FLAG_Z )
			return 1;
		break;

	case 0x05:	// C set
		if ( m_flags & FLAG_C )
			return 1;
		break;

	case 0x06:	// NLZ clear
		if ( m_flags & FLAG_LZ )
			return 1;
		break;

	case 0x07:	// unconditional
		return 1;
		break;
	}

	return 0;
}

inline UINT8 hd61700_cpu_device::make_logic(UINT8 type, UINT8 d1, UINT8 d2)
{
	switch (type&3)
	{
		case 0:	//and
			return d1 & d2;
		case 1:	//nand
			return ~(d1 & d2);
		case 2:	//or
			return d1 | d2;
		case 3:	//xor
			return d1 ^ d2;
		default:
			return 0x00;
	}
}

inline void hd61700_cpu_device::check_optional_jr(UINT8 arg)
{
	if (arg & 0x80)
	{
		if (m_pc < INT_ROM && !(m_fetch_addr&1)) read_op();

		UINT8 arg1 = read_op();

		UINT32 new_pc = m_pc + get_im_7(arg1) - 1;

		set_pc(new_pc);
		m_icount -= 3;
	}
}

inline UINT8 hd61700_cpu_device::get_sir_im8(UINT8 arg)
{
	if (((arg>>5) & 0x03) == 0x03)
	{
		UINT8 arg1 = read_op();

		return arg1&0x1f;
	}
	else
	{
		return READ_SREG(arg)&0x1f;
	}
}

inline UINT8 hd61700_cpu_device::get_sir_im8(UINT8 arg, UINT8 arg1)
{
	if (((arg>>5) & 0x03) == 0x03)
	{
		return arg1&0x1f;
	}
	else
	{
		return READ_SREG(arg)&0x1f;
	}
}

inline int hd61700_cpu_device::get_sign_mreg(UINT8 arg)
{
	int res = READ_REG(get_sir_im8(arg));

	if (arg & 0x80) res = -res;

	return res;
}

inline int hd61700_cpu_device::get_sign_im8(UINT8 arg)
{
	int res = read_op();

	if (arg & 0x80) res = -res;

	return res;
}

inline int hd61700_cpu_device::get_im_7(UINT8 data)
{
	if (data&0x80)
		return 0x80 - data;
	else
		return data;
}

inline UINT16 hd61700_cpu_device::make_bcd_sub(UINT8 arg1, UINT8 arg2)
{

	UINT32 ret = (arg1&0x0f) - (arg2&0x0f);
	UINT8 carry;

	if (ret > 0x09)
	{
		ret = (ret - 0x06) & 0x0f;
		carry = 1;
	}
	else
		carry = 0;

	ret += ((arg1&0xf0) - (arg2&0xf0) - (carry<<4));

	if (ret > 0x9f)
	{
		ret = (ret - 0x60) & 0x0ff;
		carry = 1;
	}
	else
		carry = 0;

	ret -= (carry<<8);

	return ret;
}

inline UINT16 hd61700_cpu_device::make_bcd_add(UINT8 arg1, UINT8 arg2)
{
	UINT32 ret = (arg1&0x0f) + (arg2&0x0f);
	UINT8 carry;

	if (ret > 0x09)
	{
		ret = (ret + 0x06) & 0x0f;
		carry = 1;
	}
	else
		carry = 0;

	ret += ((arg1&0xf0) + (arg2&0xf0) + (carry<<4));

	if (ret > 0x9f)
	{
		ret = (ret + 0x60) & 0x0ff;
		carry = 1;
	}
	else
		carry = 0;

	ret += (carry<<8);

	return ret;
}
